﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{
    public class RevolvedSurface3d : Surface3d
    {
        public Curve3d Curve { get; private set; }
        public Vector3 Origin { get; private set; }
        public Vector3 Axis { get; private set;}
        public double StartAngle { get; private set;}
        public double EndAngle { get; private set;}

        public RevolvedSurface3d(Curve3d curve, Vector3 origin, Vector3 axis, double startAngle, double endAngle)
        {
            this.Curve = curve;
            this.Origin = origin;
            this.Axis = axis;
            this.StartAngle = startAngle;
            this.EndAngle = endAngle;

            double angle = endAngle - startAngle;
            double angleDiv = angle / Revolve3d.TempSegments;
            var points = curve.GetPoints();
            var pStart = points.First();
            var pEnd = points.Last();
            var cenStart = GetProjectionPoint(pStart);
            var cenEnd = GetProjectionPoint(pEnd);


            var arcStart = new Arc3d(cenStart, pStart.DistanceTo(cenStart), startAngle, endAngle)
            {
                Normal = axis
            };
            var arcEnd = new Arc3d(cenEnd, pEnd.DistanceTo(cenEnd), endAngle, startAngle, true)
            {
                Normal = axis
            };
            var curveStart = curve.Clone().RotateRoundAxis(origin, axis, startAngle).Reverse();
            var curveEnd = curve.Clone().RotateRoundAxis(origin, axis, endAngle);
            this.OuterLoop = new List<Curve3d>
            { 
                arcStart,
                curveEnd,
                arcEnd,
                curveStart
            };

        }

        private Vector3 GetProjectionPoint(Vector3 vec)
        {
            var dir = (vec - this.Origin).Normalize();
            var angle = dir.AngleTo(this.Axis);
            var hypotenuse = vec.DistanceTo(this.Origin); //斜边长度
            var adjacentSide = hypotenuse * Math.Cos(angle); //邻边

            return this.Origin + (this.Axis * adjacentSide);
        }

        public override Tuple<double[], int[]> Trianglate()
        {
            double angle = this.EndAngle - this.StartAngle;
            double angleDiv = angle / Revolve3d.TempSegments;
            var allPoints = new ListEx<Vector3>();
            var indices = new ListEx<int>();

            var points = this.Curve.GetPoints();
            for (int i = 0; i < points.Count; i++)
            {
                int nxi = (i + 1) % points.Count;
                for (int j = 0; j <= Revolve3d.TempSegments - 1; j++)
                {
                    var nxj = j + 1;
                    var p1 = points[i].Clone().RotateRoundAxis(this.Origin, this.Axis, j * angleDiv);
                    var p2 = points[nxi].Clone().RotateRoundAxis(this.Origin, this.Axis, j * angleDiv);
                    var p3 = points[i].Clone().RotateRoundAxis(this.Origin, this.Axis, nxj * angleDiv);
                    var p4 = points[nxi].Clone().RotateRoundAxis(this.Origin, this.Axis, nxj * angleDiv);

                    var count = allPoints.Count;
                    indices.Push(count, count + 1, count + 2);
                    allPoints.Push(p1, p3, p2);

                    count = allPoints.Count;
                    indices.Push(count, count + 1, count + 2);
                    allPoints.Push(p1, p4, p3);
                }
            }

            var posArr = Utils.GenerateVertexArr(allPoints);
            return new Tuple<double[], int[]>(posArr, indices.ToArray());
        }
    }
}